package diversion.v1.security;

//~--- non-JDK imports --------------------------------------------------------

import diversion.v1.util.Base64;

//~--- JDK imports ------------------------------------------------------------

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;

import java.math.BigInteger;

import java.security.InvalidAlgorithmParameterException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.KeyAgreement;
import javax.crypto.SecretKey;
import javax.crypto.interfaces.DHPrivateKey;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.DHParameterSpec;

/**
 *  Description of the Class
 *
 * @author    jmricker
 */
public class KeyGen {
    final static int        L = 1023;
    final static BigInteger P =
        new BigInteger(
            "113088835522265060568527929018471165217699581971856781365267878545638178249200881492073281803890722992505330296225084688780957732592098449042298365675411317360741255176060289466224887145017395423512953311777674475413741076024194415914280417905423171349380121799205921721241930630401168299371506553817248819401");
    final static BigInteger G =
        new BigInteger(
            "39181998666640298816399146949435044750661115957394095794586383930503320013031687794011009886732730054906151766741662074338727040902782498244489007775378250286763240513854705251553152171759648948654931173219818429275590837029447299373634752262779337562805439075102438089774735522388680297612303971156319730825");

    /**
     *  Description of the Method
     *
     * @return                                             Description of the Return
     *      Value
     * @exception  java.security.GeneralSecurityException  Description of the
     *      Exception
     */
    public static KeyPair generateKeys() throws java.security.GeneralSecurityException {
        try {
            KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH");

            keyGen.initialize(new DHParameterSpec(P, G, L));

            return keyGen.generateKeyPair();
        } catch (NoSuchAlgorithmException e) {
            throw new java.security.GeneralSecurityException(e.toString());
        } catch (InvalidAlgorithmParameterException e) {
            throw new java.security.GeneralSecurityException(e.toString());
        }
    }

    /**
     *  Description of the Method
     *
     * @param  filename         Description of the Parameter
     * @return                  Description of the Return Value
     * @exception  IOException  Description of the Exception
     */
    public static KeyPair loadKeys(String filename) throws IOException {
        try {
            File              file = new File(filename);
            ObjectInputStream in   = new ObjectInputStream(new FileInputStream(file));
            KeyPair           pair = (KeyPair) in.readObject();

            in.close();

            return pair;
        } catch (ClassNotFoundException e) {}

        return null;
    }

    /**
     *  Description of the Method
     *
     * @param  encoded                                     Description of the
     *      Parameter
     * @return                                             Description of the Return
     *      Value
     * @exception  java.security.GeneralSecurityException  Description of the
     *      Exception
     */
    public static DHPublicKey restoreKey(String encoded) throws java.security.GeneralSecurityException {
        try {
            byte[]             keyBytes    = Base64.decode(encoded);
            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
            KeyFactory         keyFact     = KeyFactory.getInstance("DH");

            return (DHPublicKey) keyFact.generatePublic(x509KeySpec);
        } catch (java.security.NoSuchAlgorithmException e) {
            throw new java.security.GeneralSecurityException(e.toString());
        } catch (java.security.spec.InvalidKeySpecException e) {
            throw new java.security.GeneralSecurityException(e.toString());
        } catch (NullPointerException e) {
            throw new java.security.GeneralSecurityException(e.toString());
        }
    }

    /**
     *  Description of the Method
     *
     * @param  publicKey                                   Description of the
     *      Parameter
     * @param  privateKey                                  Description of the
     *      Parameter
     * @return                                             Description of the Return
     *      Value
     * @exception  java.security.GeneralSecurityException  Description of the
     *      Exception
     */
    public static SecretKey generateSecretKey(DHPublicKey publicKey, DHPrivateKey privateKey)
            throws java.security.GeneralSecurityException {
        if ((publicKey == null) || (privateKey == null)) {
            return null;
        }

        try {
            KeyAgreement ka = KeyAgreement.getInstance("DH");

            ka.init(privateKey);
            ka.doPhase(publicKey, true);

            return ka.generateSecret("DES");
        } catch (java.security.NoSuchAlgorithmException e) {
            throw new java.security.GeneralSecurityException(e.toString());
        } catch (java.security.InvalidKeyException e) {
            throw new java.security.GeneralSecurityException(e.toString());
        }
    }

    /**
     *  Description of the Method
     *
     * @param  filename  Description of the Parameter
     * @param  keys      Description of the Parameter
     */
    public static void saveKeys(String filename, KeyPair keys) {
        try {
            ObjectOutput out = new ObjectOutputStream(new FileOutputStream(filename));

            out.writeObject(keys);
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     *  The main program for the KeyGen class
     *
     * @param  args  The command line arguments
     */
    public static void main(String[] args) {
        sun.misc.BASE64Encoder encoder = new sun.misc.BASE64Encoder();
        sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder();

        try {
            KeyPair pair    = KeyGen.generateKeys();
            String  public1 = Base64.encodeBytes(pair.getPublic().getEncoded(), Base64.GZIP);
            String  public2 = Base64.encodeBytes(pair.getPublic().getEncoded());
            String  public3 = encoder.encode(pair.getPublic().getEncoded());

            System.out.println("Public Key " + public1.length() + " = " + public1 + "\n");
            System.out.println("Public Key " + public2.length() + " = " + public2 + "\n");
            System.out.println("Public Key " + public3.length() + " = " + public3 + "\n");
        } catch (java.security.GeneralSecurityException e) {
            e.printStackTrace();
        }
    }
}


//~ Formatted by Jindent --- http://www.jindent.com
